Skip to content

[Rewrite] Draft-16 migration#170

Open
itzmanish wants to merge 24 commits into
cloudflare:mainfrom
itzmanish:draft-16-rewrite
Open

[Rewrite] Draft-16 migration#170
itzmanish wants to merge 24 commits into
cloudflare:mainfrom
itzmanish:draft-16-rewrite

Conversation

@itzmanish
Copy link
Copy Markdown
Contributor

NOTE - Please use this branch instead of older #131 because that is not compatible with base branch.

itzmanish added 24 commits May 6, 2026 15:01
Replace Announce/Announced types with PublishNamespace/PublishedNamespace
throughout moq-transport, moq-relay-ietf, moq-pub, moq-clock-ietf, and
moq-test-client. The wire messages were already named correctly; this
aligns the session-layer API and test case names with the spec terminology.

Also replace .lock().unwrap() on mutex acquisitions with explicit poison
error handling in publisher.rs and subscriber.rs.
Key-Value-Pairs now use delta-encoded types per §1.4.2: each Delta Type
on the wire is the difference from the previous absolute type (or 0 for
the first pair in a sequence). KeyValuePairs::encode sorts by ascending
key before emitting deltas; decode accumulates the running type and
rejects overflow. ExtensionHeaders shares the same delta scheme,
threading prev through its own encode/decode loop.

The Decode/Encode trait impls on KeyValuePair are removed to prevent
context-free single-pair misuse. All callers must go through
decode_with_prev/encode_with_prev, or the KeyValuePairs/ExtensionHeaders
containers which manage the prev state correctly.

TrackNamespace now enforces §2.4.1: 1-32 non-empty fields for full
namespaces; zero-count or zero-length fields produce errors. Adds
TrackNamespacePrefix (0-32 fields, empty allowed) for SUBSCRIBE_NAMESPACE
use, and full_track_name_len() helper for the 4096-byte limit check.

New error variants added to DecodeError and EncodeError for each new
validation rule.
Version negotiation now uses ALPN only. The native QUIC ALPN identifier
changes from 'moq-00' to 'moqt-16'. CLIENT_SETUP and SERVER_SETUP no
longer carry a version list or selected version in their payloads; both
messages carry setup parameters only.

For native moqt:// connections the client now sends AUTHORITY (host:port)
and PATH (path?query) setup parameters as required by draft-16 §9.3.1.1
and §9.3.1.2. The server-side version negotiation code and
largest_common helper are removed since version is agreed at the ALPN
layer.

Adds Version::DRAFT_16 constant. Removes SessionError::Version as it is
no longer reachable. Updates mlog events to match the new setup message
shape.
…ge length

Adds three new draft-16 message types:
- REQUEST_OK (0x07): shared positive response for REQUEST_UPDATE,
  TRACK_STATUS, SUBSCRIBE_NAMESPACE, and PUBLISH_NAMESPACE
- REQUEST_ERROR (0x05): shared negative response with Request ID,
  Error Code, Retry Interval, and reason phrase; replaces per-request
  error messages from earlier drafts
- REQUEST_UPDATE (0x02): replaces SubscribeUpdate; carries
  Request ID, Existing Request ID, and parameters

Wire IDs in the message table are corrected to match draft-16 Table 1.
Legacy messages that had conflicting IDs (SubscribeError, PublishNamespaceOk,
PublishNamespaceError, TrackStatusOk/Error, etc.) are reassigned to
internal stub IDs (0x100+) so existing session dispatch compiles.

The control message decode macro now enforces the 16-bit Length field:
the payload is read into an exact-size slice and any remaining bytes
after decoding produce a PROTOCOL_VIOLATION error.
Add a session-level RequestId manager with independent send and receive state under one shared handle. Publisher and Subscriber share outbound allocation so local requests use one monotonically increasing sequence, while inbound validation checks the peer sequence separately.

Outbound allocation enforces the peer MAX_REQUEST_ID and emits REQUESTS_BLOCKED once per blocked limit. Incoming MAX_REQUEST_ID updates the outbound budget and must strictly increase. Incoming REQUESTS_BLOCKED increases the local advertised maximum and queues MAX_REQUEST_ID.

Session receive handling now validates sequenced request IDs and handles GOAWAY, MAX_REQUEST_ID, and REQUESTS_BLOCKED directly. Add SessionError variants for INVALID_REQUEST_ID, TOO_MANY_REQUESTS, and PROTOCOL_VIOLATION.
PUBLISH_NAMESPACE_DONE now carries Request ID (not namespace) per §9.22.
PUBLISH_NAMESPACE_CANCEL now carries Request ID (not namespace) per §9.24.

Acceptance of PUBLISH_NAMESPACE is now sent as REQUEST_OK (§9.7) instead
of the legacy PUBLISH_NAMESPACE_OK. Rejection is sent as REQUEST_ERROR
(§9.8) instead of the legacy PUBLISH_NAMESPACE_ERROR.

Session dispatch routes incoming REQUEST_OK and REQUEST_ERROR from the
subscriber to the PUBLISH_NAMESPACE state by request ID. RequestOk and
RequestError added to the subscriber role enum so published_namespace.rs
can send them.

PublishedNamespaceRecv now carries the request ID so PUBLISH_NAMESPACE_DONE
and CANCEL can be looked up without a namespace key. drop_publish_namespace
returns the removed recv value so callers can invoke recv_error or recv_done
directly on it.
Subscription rejections (before SUBSCRIBE_OK) now use REQUEST_ERROR
(draft-16 §9.8) instead of the legacy SUBSCRIBE_ERROR. The error code
defaults to InternalError since ServeError does not map directly to a
specific REQUEST_ERROR code at this layer.

Duplicate SUBSCRIBE (same request ID) now sends REQUEST_ERROR with
DUPLICATE_SUBSCRIPTION (0x19) per draft-16 §5.1 instead of closing the
session. This is a per-request error, not a session-level violation.

recv_subscribe_error is kept for exhaustive match but annotated as a
legacy stub — stub ID 0x100 is never produced by the wire decoder so
draft-16 subscription rejections only arrive as REQUEST_ERROR.
Add PUBLISH_DONE status code enum (§13.4.3) and map ServeError variants
to the correct codes. TrackEnded is used for normal completion,
InternalError for unexpected errors, and Closed passes through the
application-specific code.

Track the number of subgroup streams opened per subscription in
SubscribedState so PUBLISH_DONE reports an accurate stream_count.
Datagram-only subscriptions remain stream_count=0.

UNSUBSCRIBE now removes publisher-side subscription state immediately
and marks the subscription as unsubscribed. The Drop impl skips sending
PUBLISH_DONE or REQUEST_ERROR when unsubscribed is set, since the
subscriber already terminated and sending a terminal message would be
spurious.
respond_ok now sends REQUEST_OK (§9.7) with a LARGEST_OBJECT parameter
when objects have been published on the track. No Track Alias is included
since draft-16 §9.19 does not use one for TRACK_STATUS responses.

respond_error now sends REQUEST_ERROR (§9.8) instead of the legacy
TRACK_STATUS_ERROR. Callers updated to use RequestErrorCode values:
InternalError for the unknown-queue-full case, DoesNotExist for the
relay track-not-found case.
Draft-16 §10.2.1.1 only allows Normal (0x0), EndOfGroup (0x3), and
EndOfTrack (0x4). The value 0x1 existed in earlier drafts but was
removed. Any received 0x1 or other unknown value now returns
InvalidObjectStatus instead of silently succeeding.
Draft-16 §4: limited endpoints SHOULD respond with NOT_SUPPORTED rather
than ignoring incoming request types they do not implement.

Publisher-side: FETCH, REQUEST_UPDATE, and SUBSCRIBE_NAMESPACE now each
send REQUEST_ERROR NOT_SUPPORTED back to the peer instead of returning a
session-closing error. FETCH_CANCEL and UNSUBSCRIBE_NAMESPACE reference
existing requests and are logged then ignored.

Subscriber-side: PUBLISH (publisher-initiated subscription) now sends
REQUEST_ERROR NOT_SUPPORTED. Legacy response stubs that can never arrive
from a draft-16 peer are logged and ignored instead of closing the session.
Update metric description strings in moq-relay-ietf to reference
PUBLISH_NAMESPACE and REQUEST_OK instead of ANNOUNCE/ANNOUNCE_OK.
Metric names themselves are unchanged to avoid breaking existing
dashboards and alerting rules.

Update the RawQuic transport doc comment to reflect the correct
ALPN string moqt-16 instead of the old moq-00.
# Conflicts:
#	moq-relay-ietf/src/relay.rs
#	moq-transport/src/session/subscriber.rs
- Move filter_type, subscriber_priority, group_order, and forward
  from message fields into SUBSCRIBE parameters per draft-16
- Add SubscriptionFilter parameter encoding/decoding
- Introduce TrackName newtype to replace bare String track names
- Simplify SubscribeOk and TrackStatus to draft-16 field sets
- Add DeliveryFilter for applying subscription filters to objects
  and datagrams at serve time
- Reject duplicate subscriptions by FullTrackName on the publisher
- Fix subgroup object ID delta computation and defer subgroup writer
  creation until the first object is received
- Add Namespace and NamespaceDone message variants
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant